<?php
declare(strict_types=1);

namespace App\Repository;

use Hyperf\Redis\Redis;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Contract\StdoutLoggerInterface;

/**
 * Redis 缓存基类
 */
abstract class BaseCacheRepository
{
    #[Inject]
    protected ?Redis $redis = null;  // 使用可为空的类型

    #[Inject]
    protected ?StdoutLoggerInterface $logger = null;

    /**
     * 获取 Redis 实例（确保已初始化）
     */
    protected function getRedis(): Redis
    {
        if ($this->redis === null) {
            throw new \RuntimeException('Redis 实例未初始化');
        }
        return $this->redis;
    }

    /**
     * 获取 Logger 实例（确保已初始化）
     */
    protected function getLogger(): StdoutLoggerInterface
    {
        if ($this->logger === null) {
            throw new \RuntimeException('Logger 实例未初始化');
        }
        return $this->logger;
    }

    /**
     * 获取缓存键前缀
     */
    abstract protected function getKeyPrefix(): string;

    /**
     * 生成完整的缓存键
     */
    protected function buildKey(string $key): string
    {
        $prefix = $this->getKeyPrefix();
        return $prefix ? "{$prefix}:{$key}" : $key;
    }

    /**
     * 设置缓存
     */
    public function set(string $key, $value, int $ttl = 3600): bool
    {
        try {
            $redis = $this->getRedis();
            $fullKey = $this->buildKey($key);
            $serializedValue = is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE);

            if ($ttl > 0) {
                return $redis->setex($fullKey, $ttl, $serializedValue);
            }

            return $redis->set($fullKey, $serializedValue);
        } catch (\Throwable $e) {
            $this->getLogger()->error("Redis SET 失败: {$e->getMessage()}");
            return false;
        }
    }

    /**
     * 获取缓存
     */
    public function get(string $key)
    {
        try {
            $redis = $this->getRedis();
            $fullKey = $this->buildKey($key);
            $value = $redis->get($fullKey);

            if ($value === false) {
                return null;
            }

            // 尝试 JSON 解码
            $decoded = json_decode($value, true);
            return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
        } catch (\Throwable $e) {
            $this->getLogger()->error("Redis GET 失败: {$e->getMessage()}");
            return null;
        }
    }

    /**
     * 删除缓存
     */
    public function delete(string $key): bool
    {
        try {
            $redis = $this->getRedis();
            $fullKey = $this->buildKey($key);
            return (bool) $redis->del($fullKey);
        } catch (\Throwable $e) {
            $this->getLogger()->error("Redis DEL 失败: {$e->getMessage()}");
            return false;
        }
    }

    /**
     * 检查缓存是否存在
     */
    public function exists(string $key): bool
    {
        try {
            $redis = $this->getRedis();
            $fullKey = $this->buildKey($key);
            return (bool) $redis->exists($fullKey);
        } catch (\Throwable $e) {
            $this->getLogger()->error("Redis EXISTS 失败: {$e->getMessage()}");
            return false;
        }
    }

    /**
     * 自增操作
     */
    public function incr(string $key, int $value = 1): int
    {
        try {
            $redis = $this->getRedis();
            $fullKey = $this->buildKey($key);
            return $redis->incrBy($fullKey, $value);
        } catch (\Throwable $e) {
            $this->getLogger()->error("Redis INCR 失败: {$e->getMessage()}");
            return 0;
        }
    }

    /**
     * 自减操作
     */
    public function decr(string $key, int $value = 1): int
    {
        try {
            $redis = $this->getRedis();
            $fullKey = $this->buildKey($key);
            return $redis->decrBy($fullKey, $value);
        } catch (\Throwable $e) {
            $this->getLogger()->error("Redis DECR 失败: {$e->getMessage()}");
            return 0;
        }
    }
}